<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1170760
-->
<head>
  <meta charset="utf-8">
  <title>Test for Bug 1170760</title>
  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1170760">Mozilla Bug 1170760</a>
<p id="display"></p>
<div id="content" style="display: none">
<iframe id="t" src="http://example.org/chrome/dom/promise/tests/file_promise_xrays.html"></iframe>
</div>

<pre id="test">
<script type="application/javascript">

var win = $("t").contentWindow;

/** Test for Bug 1170760 **/
SimpleTest.waitForExplicitFinish();

function testLoadComplete() {
  is(win.location.href, $("t").src, "Should have loaded the right thing");
  nextTest();
}

function testHaveXray() {
  is(typeof win.Promise.race, "function", "Should see a race() function");
  var exception;
  try {
    win.Promise.wrappedJSObject.race;
  } catch (e) {
    exception = e;
  }
  is(exception, "Getting race", "Should have thrown the right exception");
  is(win.wrappedJSObject.setupThrew, false, "Setup should not have thrown");
  nextTest();
}

function testConstructor1() {
  var p = new win.Promise(function(resolve, reject) { resolve(win.Promise.resolve(5)); });
  p.then(
    function(arg) {
      is(arg, 5, "Content Promise constructor resolved with content promise should work");
    },
    function(e) {
      ok(false, "Content Promise constructor resolved with content promise should not fail");
    }
  ).then(nextTest);
}

function testConstructor2() {
  var p = new win.Promise(function(resolve, reject) { resolve(Promise.resolve(5)); });
  p.then(
    function(arg) {
      is(arg, 5, "Content Promise constructor resolved with chrome promise should work");
    },
    function(e) {
      ok(false, "Content Promise constructor resolved with chrome promise should not fail");
    }
  ).then(nextTest);
}

function testRace1() {
  var p = win.Promise.race(new win.Array(1, 2));
  p.then(
    function(arg) {
      ok(arg == 1 || arg == 2,
         "Should get the right value when racing content-side array");
    },
    function(e) {
      ok(false, "testRace1 threw exception: " + e);
    }
  ).then(nextTest);
}

function testRace2() {
  var p = win.Promise.race(
    new Array(win.Promise.resolve(1), win.Promise.resolve(2)));
  p.then(
    function(arg) {
      ok(arg == 1 || arg == 2,
         "Should get the right value when racing content-side array of explicit Promises");
    },
    function(e) {
      ok(false, "testRace2 threw exception: " + e);
    }
  ).then(nextTest);
}

function testRace3() {
  // This works with a chrome-side array because we do the iteration
  // while still in the Xray compartment.
  var p = win.Promise.race([1, 2]);
  p.then(
    function(arg) {
      ok(arg == 1 || arg == 2,
         "Should get the right value when racing chrome-side array");
    },
    function(e) {
      ok(false, "testRace3 threw exception: " + e);
    }
  ).then(nextTest);
}

function testRace4() {
  // This works with both content-side and chrome-side Promises because we want
  // it to and go to some lengths to make it work.
  var p = win.Promise.race([Promise.resolve(1), win.Promise.resolve(2)]);
  p.then(
    function(arg) {
      ok(arg == 1 || arg == 2,
         "Should get the right value when racing chrome-side promises");
    },
    function(e) {
      ok(false, "testRace4 threw exception: " + e);
    }
  ).then(nextTest);
}

function testAll1() {
  var p = win.Promise.all(new win.Array(1, 2));
  p.then(
    function(arg) {
      ok(arg instanceof win.Array, "Should get an Array from Promise.all (1)");
      is(arg[0], 1, "First entry of Promise.all return value should be correct (1)");
      is(arg[1], 2, "Second entry of Promise.all return value should be correct (1)");
    },
    function(e) {
      ok(false, "testAll1 threw exception: " + e);
    }
  ).then(nextTest);
}

function testAll2() {
  var p = win.Promise.all(
    new Array(win.Promise.resolve(1), win.Promise.resolve(2)));
  p.then(
    function(arg) {
      ok(arg instanceof win.Array, "Should get an Array from Promise.all (2)");
      is(arg[0], 1, "First entry of Promise.all return value should be correct (2)");
      is(arg[1], 2, "Second entry of Promise.all return value should be correct (2)");
    },
    function(e) {
      ok(false, "testAll2 threw exception: " + e);
    }
  ).then(nextTest);
}

function testAll3() {
  // This works with a chrome-side array because we do the iteration
  // while still in the Xray compartment.
  var p = win.Promise.all([1, 2]);
  p.then(
    function(arg) {
      ok(arg instanceof win.Array, "Should get an Array from Promise.all (3)");
      is(arg[0], 1, "First entry of Promise.all return value should be correct (3)");
      is(arg[1], 2, "Second entry of Promise.all return value should be correct (3)");
    },
    function(e) {
      ok(false, "testAll3 threw exception: " + e);
    }
  ).then(nextTest);
}

function testAll4() {
  // This works with both content-side and chrome-side Promises because we want
  // it to and go to some lengths to make it work.
  var p = win.Promise.all([Promise.resolve(1), win.Promise.resolve(2)]);
  p.then(
    function(arg) {
      ok(arg instanceof win.Array, "Should get an Array from Promise.all (4)");
      is(arg[0], 1, "First entry of Promise.all return value should be correct (4)");
      is(arg[1], 2, "Second entry of Promise.all return value should be correct (4)");
    },
    function(e) {
      ok(false, "testAll4 threw exception: " + e);
    }
  ).then(nextTest);
}

function testAll5() {
  var p = win.Promise.all(new win.Array());
  p.then(
    function(arg) {
      ok(arg instanceof win.Array, "Should get an Array from Promise.all (5)");
    },
    function(e) {
      ok(false, "testAll5 threw exception: " + e);
    }
  ).then(nextTest);
}

function testResolve1() {
  var p = win.Promise.resolve(5);
  ok(p instanceof win.Promise, "Promise.resolve should return a promise");
  p.then(
    function(arg) {
      is(arg, 5, "Should get correct Promise.resolve value");
    },
    function(e) {
      ok(false, "testAll5 threw exception: " + e);
    }
  ).then(nextTest);
}

function testResolve2() {
  var p = win.Promise.resolve(5);
  var q = win.Promise.resolve(p);
  is(q, p, "Promise.resolve should just pass through Promise values");
  nextTest();
}

function testResolve3() {
  var p = win.Promise.resolve(Promise.resolve(5));
  p.then(
    function(arg) {
      is(arg, 5, "Promise.resolve with chrome Promise should work");
    },
    function(e) {
      ok(false, "Promise.resolve with chrome Promise should not fail");
    }
  ).then(nextTest);
}

function testResolve4() {
  var p = new win.Promise((res, rej) => {});
  Components.utils.getJSTestingFunctions().resolvePromise(p, 42);
  p.then(
    function(arg) {
      is(arg, 42, "Resolving an Xray to a promise with TestingFunctions resolvePromise should work");
    },
    function(e) {
      ok(false, "Resolving an Xray to a promise with TestingFunctions resolvePromise should not fail");
    }
  ).then(nextTest);
}

function testReject1() {
  var p = win.Promise.reject(5);
  ok(p instanceof win.Promise, "Promise.reject should return a promise");
  p.then(
    function(arg) {
      ok(false, "Promise should be rejected");
    },
    function(e) {
      is(e, 5, "Should get correct Promise.reject value");
    }
  ).then(nextTest);
}

function testReject2() {
  var p = new win.Promise((res, rej) => {});
  Components.utils.getJSTestingFunctions().rejectPromise(p, 42);
  p.then(
    function(arg) {
      ok(false, "Rejecting an Xray to a promise with TestingFunctions rejectPromise should trigger catch handler");
    },
    function(e) {
      is(e, 42, "Rejecting an Xray to a promise with TestingFunctions rejectPromise should work");
    }
  ).then(nextTest);
}

function testThen1() {
  var p = win.Promise.resolve(5);
  var q = p.then((x) => x*x);
  ok(q instanceof win.Promise,
     "Promise.then should return a promise from the right global");
  q.then(
    function(arg) {
      is(arg, 25, "Promise.then should work");
    },
    function(e) {
      ok(false, "Promise.then should not fail");
    }
  ).then(nextTest);
}

function testThen2() {
  var p = win.Promise.resolve(5);
  var q = p.then((x) => Promise.resolve(x*x));
  ok(q instanceof win.Promise,
     "Promise.then should return a promise from the right global");
  q.then(
    function(arg) {
      is(arg, 25, "Promise.then resolved with chrome promise should work");
    },
    function(e) {
      ok(false, "Promise.then resolved with chrome promise should not fail");
    }
  ).then(nextTest);
}

function testCatch1() {
  var p = win.Promise.reject(5);
  ok(p instanceof win.Promise, "Promise.reject should return a promise");
  var q = p.catch((x) => x*x);
  ok(q instanceof win.Promise,
     "Promise.catch should return a promise from the right global");
  q.then(
    function(arg) {
      is(arg, 25, "Promise.catch should work");
    },
    function(e) {
      ok(false, "Promise.catch should not fail");
    }
  ).then(nextTest);
}

function testToStringTag1() {
  is(win.Promise.prototype[Symbol.toStringTag], "Promise", "@@toStringTag was incorrect");
  var p = win.Promise.resolve();
  is(String(p), "[object Promise]", "String() result was incorrect");
  is(p.toString(), "[object Promise]", "toString result was incorrect");
  is(Object.prototype.toString.call(p), "[object Promise]", "second toString result was incorrect");
  nextTest();
}

var tests = [
  testLoadComplete,
  testHaveXray,
  testConstructor1,
  testConstructor2,
  testRace1,
  testRace2,
  testRace3,
  testRace4,
  testAll1,
  testAll2,
  testAll3,
  testAll4,
  testAll5,
  testResolve1,
  testResolve2,
  testResolve3,
  testResolve4,
  testReject1,
  testReject2,
  testThen1,
  testThen2,
  testCatch1,
  testToStringTag1,
];

function nextTest() {
  if (tests.length == 0) {
    SimpleTest.finish();
    return;
  }
  tests.shift()();
}

addLoadEvent(nextTest);

</script>
</pre>
</body>
</html>
